pub trait ProtoDecode<'de> {
    fn decode(buf: &'de [u8]) -> Option<Self>
    where
        Self: Sized;
}

pub trait ProtoSize {
    fn size(&self) -> usize;
}

impl ProtoSize for u8 {
    #[inline(always)]
    fn size(&self) -> usize {
        1
    }
}

impl ProtoSize for i8 {
    #[inline(always)]
    fn size(&self) -> usize {
        1
    }
}

impl ProtoSize for u16 {
    #[inline(always)]
    fn size(&self) -> usize {
        2
    }
}

impl ProtoSize for i16 {
    #[inline(always)]
    fn size(&self) -> usize {
        2
    }
}

impl ProtoSize for u32 {
    #[inline(always)]
    fn size(&self) -> usize {
        4
    }
}

impl ProtoSize for i32 {
    #[inline(always)]
    fn size(&self) -> usize {
        4
    }
}

impl ProtoSize for &[u8] {
    #[inline(always)]
    fn size(&self) -> usize {
        self.len() + 1
    }
}

impl<'de> ProtoDecode<'de> for &'de [u8] {
    fn decode(buf: &'de [u8]) -> Option<Self>
    where
        Self: Sized,
    {
        let len = buf.len();
        if len < 1 {
            None
        } else {
            let n = buf[0] as usize;
            if len < (n + 1) {
                None
            } else {
                Some(&buf[1..(1 + n)])
            }
        }
    }
}

impl<'de> ProtoDecode<'de> for u8 {
    fn decode(buf: &[u8]) -> Option<Self>
    where
        Self: Sized,
    {
        if buf.len() < 1 {
            None
        } else {
            Some(buf[0])
        }
    }
}

impl<'de> ProtoDecode<'de> for i8 {
    fn decode(buf: &[u8]) -> Option<Self>
    where
        Self: Sized,
    {
        if buf.len() < 1 {
            None
        } else {
            Some(buf[0] as Self)
        }
    }
}

impl<'de> ProtoDecode<'de> for u16 {
    fn decode(buf: &'de [u8]) -> Option<Self>
    where
        Self: Sized,
    {
        if buf.len() < 2 {
            None
        } else {
            let v = ((buf[0] as Self) << 8) | (buf[1] as Self);
            Some(v)
        }
    }
}

impl<'de> ProtoDecode<'de> for i16 {
    fn decode(buf: &'de [u8]) -> Option<Self>
    where
        Self: Sized,
    {
        if buf.len() < 2 {
            None
        } else {
            let v = ((buf[0] as Self) << 8) | (buf[1] as Self);
            Some(v)
        }
    }
}

impl<'de> ProtoDecode<'de> for u32 {
    fn decode(buf: &'de [u8]) -> Option<Self>
    where
        Self: Sized,
    {
        if buf.len() < 4 {
            None
        } else {
            let v = ((buf[0] as Self) << 24)
                | ((buf[1] as Self) << 16)
                | ((buf[2] as Self) << 8)
                | (buf[3] as Self);
            Some(v)
        }
    }
}

impl<'de> ProtoDecode<'de> for i32 {
    fn decode(buf: &'de [u8]) -> Option<Self>
    where
        Self: Sized,
    {
        if buf.len() < 4 {
            None
        } else {
            let v = ((buf[0] as Self) << 24)
                | ((buf[1] as Self) << 16)
                | ((buf[2] as Self) << 8)
                | (buf[3] as Self);
            Some(v)
        }
    }
}

impl<'de, T1: ProtoDecode<'de> + ProtoSize, T2: ProtoDecode<'de>> ProtoDecode<'de> for (T1, T2) {
    fn decode(buf: &'de [u8]) -> Option<Self>
    where
        Self: Sized,
    {
        let t1 = T1::decode(buf)?;
        let n1 = t1.size();
        let t2 = T2::decode(&buf[n1..])?;
        Some((t1, t2))
    }
}



